import type { MenuHandleTable, MenuManageData, MenuTable, MenuType } from '@/types/menu'
import { ElMessage } from 'element-plus'
import { computed, ref } from 'vue'
import { getJwt } from './token'

/**
 * 生成前端展示菜单树形结构
 * 这个数据是用于渲染菜单组件的
 * 不参与到Vue-Router 的路由表数据中
 * 这里的数据为属性结构 且没有 组件加载函数
 * @param menus 后端路由数据
 * @returns
 */
export function formatMenu(menus: MenuTable[]) {
  menus = menus.sort((d1, d2) => {
    return (d1.sort || 1) - (d2.sort || 1)
  })
  function crateRoute(pid: number): MenuType[] {
    // 查找所有的 根路由
    let r: MenuType[] = []
    let m = menus.filter((d) => {
      if (d.parent === pid) {
        return true
      }
    })
    m.forEach((d) => {
      let child = crateRoute(d.mId!)
      r.push({
        path: d.path!,
        name: d.key,
        children: child,
        meta: {
          icon: d.icon!,
          iconType: d.iconType!,
          show: d.faceShow == '1' ? true : false,
          disabled: d.status == '1' ? false : true,
          pid: d.parent || 0,
          key: d.key!,
          id: d.mId!,
          name: d.name!,
          comPath: d.component!
        }
      })
    })
    return r
  }
  return crateRoute(0)
}

/**
 * 所有的组件数据
 */
export const componentMap = new Map<string, Function>()
/**
 * 安装所有组件数据的映射关系
 */
function comInstall() {
  const components = import.meta.glob('@/views/**/*.vue')
  for (let fN in components) {
    let path = fN.replace('/src/views/', '').replace('.vue', '')
    let fun = components[fN]
    componentMap.set(path, fun)
  }
}
comInstall()
/**
 * 根据后端传递过来的用户菜单数据
 * 格式化为 Vue—Router 中的 路由表
 * 这里会放弃树形结构但是能够保证页面的正确跳转
 * @param menus 原始菜单数据
 * @returns
 */
export function formatRoutes(menus: MenuTable[]) {
  let r: MenuType[] = []
  menus.forEach((d) => {
    r.push({
      path: d.path!,
      name: d.key,
      component: () => {
        const confun = componentMap.get(d.component!)
        if (typeof confun === 'function') {
          return confun()
        } else {
          ElMessage.error('页面组件加载出错')
          return Promise.reject('')
        }
      },
      children: [],
      meta: {
        icon: d.icon!,
        iconType: d.iconType!,
        show: d.faceShow == '1' ? true : false,
        disabled: d.status == '1' ? false : true,
        pid: d.parent || 0,
        key: d.key!,
        id: d.mId!,
        name: d.name!,
        comPath: d.component!
      }
    })
  })
  return r
}

let menuMap: Map<number, MenuTable> = new Map()
// 开局的时候需要缓存菜单的数据
export function saveMenuMap(menus: MenuTable[]) {
  menuMap.clear()
  menus.forEach((m) => {
    menuMap.set(m.mId!, m)
  })
}
/**
 * 该函数主要用于查询一下某个路由的
 * 父路由列表
 * 在主页面包屑上需要使用
 * @param routeName 路由的名称
 * @returns 自己 + 父路列表
 */
export function searchMatched(routeName: string): MenuTable[] {
  let matched: MenuTable[] = []
  let pid = 0
  menuMap.forEach((m) => {
    if (m.key === routeName) {
      pid = m.parent || 0
      matched.push(m)
    }
  })
  function search(id: number) {
    let menu = menuMap.get(id)
    if (menu === undefined) {
      return
    } else {
      matched.unshift(menu)
      search(menu.parent || 0)
    }
  }
  search(pid)
  return matched
}

/**
 * 根据菜单的路径判断菜单是否是可用的
 * 主要用于路由跳转的时候使用
 * 因为有时候禁用了父菜单 但是子菜单没有被禁用
 * 可以通过代码去跳转或者直接使用 浏览器 导航
 * 所以跳转前需要查询一下菜单是否是可以用的
 * @param path 菜单的路径
 * @returns
 */
export function authMenu(path: string) {
  let m: MenuTable | null = null
  // 寻找用户菜单中 相匹配的 菜单
  menuMap.forEach((d) => {
    if (d.path == path) {
      m = d
    }
  })
  if (m == null) {
    return true
  }
  m = m as MenuTable
  function auth(id: number): boolean {
    let m2 = menuMap.get(id)
    // 若是没有父菜单直接 不给跳转权限
    if (m2 === undefined) {
      return false
    }
    if (m2.status === '1' && m2.parent != 0) {
      return auth(m2?.parent!)
    } else if (m2.status === '0') {
      return false
    }
    return true
  }
  return auth(m.mId!)
}

/**
 * 按钮权限标识缓存
 */
const MenuHandleMap = ref(new Map<string, MenuHandleTable>())
/* 缓存用户能够使用的菜单按钮权限标识列表 */
let canUseMenuHandle: string[] = []
/**
 * 用于保存菜单按钮数据 使用map 的方式
 * 以 按钮的权限标识符为键存放 方便查询
 * @param data 系统的菜单按钮数据
 */
export function saveMenuHandleMap(data: MenuHandleTable[]) {
  MenuHandleMap.value.clear()
  data.forEach((d) => {
    MenuHandleMap.value.set(d.tag!, d)
  })
}

// 保存系统中存在的所有 key( 按钮权限标识 )
const faceSysHandlesKey = new Set<string>()

// 权限标识保存函数
export function saveHandleKey(key: string) {
  faceSysHandlesKey.add(key)
}
/**
 * 获取所有的权限标识
 * @returns 返回所有的权限标识
 */
export function getHandleKeys() {
  return faceSysHandlesKey
}

/**
 * 保存用户的 参与鉴权的按钮
 * @param ids 能使用的id
 */
export function saveMenuHandleIds(ids: string[]) {
  canUseMenuHandle = ids
}

/**
 * 查询权限数据
 * @returns
 */
export function getMenuHandleData(tag: string) {
  return computed(() => {
    return (
      MenuHandleMap.value.get(tag) || {
        status: '0',
        show: '1',
        icon: '',
        name: '',
        type: 'success',
        tag: '',
        iconType: '',
        style: 'default'
      }
    )
  })
}
/**
 * 验证用户是否拥有 该按钮的权限
 * @param id 按钮编号
 * @returns
 */
export function authMenuHandle(id: string) {
  if (canUseMenuHandle.includes('*:*:*')) {
    return true
  }
  return canUseMenuHandle.includes(id)
}

/**
 * 创建树形菜单数据 供菜单管理页面使用
 *  */
export function formatMenuManage(data: MenuTable[]): MenuManageData[] {
  function createTree(pid: number): MenuManageData[] {
    let r: MenuManageData[] = []
    data.forEach((d) => {
      if (d.parent == pid) {
        let children = createTree(d.mId!)
        r.push({
          ...d,
          children
        })
      }
    })
    return r
  }
  return createTree(0)
}

/**
 * 随机数字加字母生成器
 * @param length 字符长度
 * @returns
 */
export function randomString(length: number) {
  let chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  let result = ''
  for (let i = 0; i < length; i++) {
    let randomIndex = Math.floor(Math.random() * chars.length)
    result += chars.charAt(randomIndex)
  }
  return result
}

export function clearUserMenus() {
  saveMenuHandleIds([])
  saveMenuMap([])
  saveMenuHandleMap([])
}
